package org.glowroot.agent.plugin.hzero._;

import org.glowroot.agent.plugin.api.Logger;
import org.glowroot.agent.plugin.api.MethodInfo;
import org.glowroot.agent.plugin.api.checker.Nullable;
import org.glowroot.agent.plugin.api.util.Reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;

public class CommonMethodMeta {
    private static final Logger logger = Logger.getLogger(CommonMethodMeta.class);

    public String initClassName;

    public String initMethodName;

    public List<Class<?>> parameterTypes;

    public ClassLoader classLoader;

    private final MethodInfo methodInfo;


    public CommonMethodMeta(MethodInfo methodInfo) {
        this.initClassName = getClassName(methodInfo);
        this.initMethodName = methodInfo.getName();
        this.parameterTypes = methodInfo.getParameterTypes();
        this.classLoader = methodInfo.getLoader();
        this.methodInfo = methodInfo;
    }

    public @Nullable Object getAnnotationValue(String annotationTypePath, String attributeName){
        try {
            Class<?> aClass = Reflection.getClassWithWarnIfNotFound(methodInfo.getDeclaringClassName(), methodInfo.getLoader());
            for (Annotation annotation : aClass.getDeclaredAnnotations()) {
                Class<? extends Annotation> annotationClass = annotation.annotationType();
                if (annotation.getClass().getName().startsWith(annotationTypePath)){
                    return getAnnotationAttribute(annotationClass, annotation, attributeName);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return null;
    }

    private static @Nullable Object getAnnotationAttribute(Class<?> pathClass, Object path, String attributeName) throws Exception {
        Method method = pathClass.getMethod(attributeName);
        return method.invoke(path);
    }

    private String getClassName(MethodInfo methodInfo) {
        Class<?> aClass = Reflection.getClassWithWarnIfNotFound(methodInfo.getDeclaringClassName(), methodInfo.getLoader());
        return aClass.getSuperclass().getSimpleName();
    }

    public String getInitClassName() {
        return initClassName;
    }

    public String getInitMethodName() {
        return initMethodName;
    }

    public List<Class<?>> getParameterTypes() {
        return parameterTypes;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }
}
